<?php

namespace app\api\middleware;

use ReflectionClass;
use support\utils\Cache;
use support\utils\Tools;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;

class SignCheckNoLoginActionMiddleware implements MiddlewareInterface
{
    private const CHECK_SIGN_NUM = 1;
    protected $error = '';

    public function process(Request $request, callable $handler): Response
    {
        // 通过反射获取控制器哪些方法不需要签名
        $controller = new ReflectionClass($request->controller);
        $noNeedSign = $controller->getDefaultProperties()['noNeedSign'] ?? [];
        // 检查当前方法是否需要签名验证
        $action = $request->action;
        if (!in_array($action, $noNeedSign)) {
            // 验证时间戳
            $time = $request->header('time', 0, 'int');
            if (!$time) {
                return $this->fail("请求签名错误 code:-3");
            }
            if ($time < (time() - 3600) || $time > (time() + 3600)) {
                return $this->fail("请求签名错误： code:-4");
            }

            // 验证设备信息
            $device = $request->header('device');
            if (!$device) {
                return $this->fail("请求签名参数缺失 -1");
            }

            // 验证版本信息
            $version = $request->header('version');
            if (!$version) {
                return $this->fail("请求签名参数缺失 -2");
            }

            // 验证客户端信息
            $client = $request->header('client');
            if (!$client) {
                return $this->fail("请求签名参数缺失 -3");
            }

            // 验证签名
            $serverSign = Tools::genSign();
            $sign = $request->header('sign');
            if ($serverSign['sign'] !== $sign) {
                return $this->fail("请求签名错误");
            }
            // 验证签名次数
            if (self::CHECK_SIGN_NUM) {
                $key = "sign:" . hash('sha256', $sign . getenv("sign_key"));
                try {
                    $num = Cache::get($key);
                    $num = $num ?: 0;
                    if ($num >= self::CHECK_SIGN_NUM) {
                        return $this->fail("请求签名过期，请刷新后重试");
                    }
                    Cache::set($key, $num + 1, 3600);
                } catch (\Exception $e) {
                    return $this->fail("系统错误，请稍后再试");
                }
            }
        }

        // 验证通过，继续处理请求
        return $handler($request);
    }

    /**
     * 失败返回
     * @param string $msg
     * @param mixed $data
     * @param int $code
     * @return Response
     */
    protected function fail($msg = 'fail', $data = null, $code = 0): Response
    {
        return json([
            'code' => $code,
            'msg'  => $msg,
            'data' => $data,
            'time' => time()
        ]);
    }

    /**
     * 生成返回数据
     */
    protected function result($msg, $data = null, $code = 0): array
    {
        return [
            'code' => $code,
            'msg'  => $msg,
            'data' => $data,
            'time' => time(),
            'sign' => request()->header('sign'),
            'used_time' => round(microtime(true) - request()->time(), 10),
            'reqs'  => request()->connection->requests
        ];
    }
}